<?php
declare (strict_types=1);

namespace app\exam\logic;

use app\common\exception\LogicException;
use app\exam\model\Special as SpecialModel;
use app\exam\model\TopicPracticeRecord as TopicPracticeRecordModel;
use app\exam\model\TopicSpecialRecord;
use think\facade\{Cache, Db};

/**
 * 试题练习记录逻辑层
 */
class TopicPracticeRecord extends TopicPracticeRecordModel
{

    /**
     * 提交知识点练习答案
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-02-04
     *
     * @param $param
     * @return void [type] [description]
     */
    public function postTopicAnswer($param)
    {
        // 数据验证
        $this->getValidate()->scene('topic_answer')->failException()->check($param);
        // 参数
        $topic_level = intval($param['topic_level']);
        $topic_id    = intval($param['topic_id']);
        $is_right    = intval($param['is_right']);

        $this->addRecord($topic_level, $topic_id, $is_right);
    }

    /**
     * 添加试题记录
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-02-04
     *
     * @param integer $topic_level  [description]
     * @param integer $topic_id     [description]
     * @param integer $is_right     [description]
     * @param integer $special_id   [description]
     * @param array   $answer       [专项答案]
     * @param integer $parent_id    [description]
     * @param integer $special_code [description]
     */
    public function addRecord(int $topic_level, int $topic_id, int $is_right, int $special_id = 0, array $answer = [], int $parent_id = 0, int $special_code = 0)
    {
        if ($special_id) {
            $redis   = Cache::store('redis')->handler();
            $special = $redis->hGet('special_topic_practice', request()->mid . '_' . $special_id);
            $special = $special ? unserialize($special) : [];
            // if ( isset($special[$topic_id]) ) unset($special[$topic_id]);
            $special[$topic_id] = ['topic_id' => $topic_id, 'is_right' => $is_right, 'answer' => $answer, 'answer_time' => time()];

            $redis->hSet('special_topic_practice', request()->mid . '_' . $special_id, serialize($special));
        }

        $ex = app(TopicPracticeRecord::class)->whereUserId(request()->mid)->whereTopicType($topic_level)->whereTopicId($topic_id)->findOrEmpty();
        //
        switch ($topic_level) {
            case 2:
                $question_type = app(TopicMaterial::class)->whereId($topic_id)->value('question_type');
                break;

            default:
                $question_type = app(Topic::class)->whereId($topic_id)->value('question_type');
                break;
        }

        Db::startTrans();
        try {
            if ($ex->isEmpty()) {
                $res = TopicPracticeRecord::create([
                    'user_id'       => request()->mid,
                    'special_id'    => $special_id,
                    'topic_type'    => $topic_level,
                    'topic_id'      => $topic_id,
                    'question_type' => $question_type,
                    'right_count'   => $is_right ? 1 : 0,
                    'wrong_count'   => $is_right ? 0 : 1,
                    'wrong_time'    => $is_right ? null : time(),
                ]);
                if ($res->isEmpty()) throw new LogicException("提交失败");
            } else {
                if ($is_right) {
                    $ex->right_count += 1;
                    $ex->wrong_time  = null;
                } else {
                    $ex->wrong_count += 1;
                    $ex->wrong_time  = time();
                }
                $ex->special_id = $special_id;
                if (!$ex->save()) throw new LogicException("提交失败");
            }

            // 记录专项正确率
            if ($special_id) $this->specialRate($special_id, $is_right, $parent_id, $special_code);
            Db::commit();
        } catch (LogicException $e) {
            Db::rollback();
            throw new LogicException($e->getMessage());
        }
    }

    public function specialRate($special_id, $is_right, $parent_id, $special_code)
    {
        // 正确率记录
        $tsr = app(TopicSpecialRecord::class)->whereUserId(request()->mid)->whereSpecialId($special_id)->whereSpecialCode($special_code)->findOrEmpty();

        if ($tsr->isEmpty()) {
            $totalCount = app(SpecialModel::class)->whereId($special_id)->value('topic_count') ?? 0;
            $accuracy   = $is_right ? round(1 / $totalCount, 2) * 100 : 0;
            $result     = TopicSpecialRecord::create([
                'user_id'      => request()->mid,
                'special_id'   => $special_id,
                'special_type' => $parent_id > 0 ? 1 : 0,
                'parent_id'    => $parent_id,
                'right_count'  => $is_right ? 1 : 0,
                'exam_count'   => $totalCount,
                'accuracy'     => $accuracy,
                'special_code' => $special_code,
            ]);
            if ($result->isEmpty()) throw new LogicException("提交失败");

            // 添加父级记录
            if ($parent_id > 0 && $parent_id != $special_id) {
                $ptsr = app(TopicSpecialRecord::class)->whereUserId(request()->mid)->whereSpecialId($parent_id)->whereSpecialCode($special_code)->findOrEmpty();
                // 修改父级记录
                if ($ptsr->isEmpty()) {
                    $parentCount     = app(SpecialModel::class)->whereId($parent_id)->value('topic_count') ?? 0;
                    $parent_accuracy = $is_right ? round(1 / $parentCount, 2) * 100 : 0;
                    $re              = TopicSpecialRecord::create([
                        'user_id'      => request()->mid,
                        'special_id'   => $parent_id,
                        'special_type' => 0,
                        'parent_id'    => 0,
                        'right_count'  => $is_right ? 1 : 0,
                        'exam_count'   => $parentCount,
                        'accuracy'     => $parent_accuracy,
                        'special_code' => $special_code,
                    ]);
                    if ($re->isEmpty()) throw new LogicException("提交失败");
                } else {
                    $ptsr->right_count += 1;
                    $ptsr->accuracy    = round($ptsr->right_count / $ptsr->exam_count, 2) * 100;
                    $ptsr->create_time = time();

                    if (!$ptsr->save()) throw new LogicException("提交失败");
                }
            }
        } else {
            if ($is_right > 0) {
                $time             = time();
                $tsr->right_count += 1;
                $tsr->accuracy    = round($tsr->right_count / $tsr->exam_count, 2) * 100;
                $tsr->create_time = $time;

                if (!$tsr->save()) throw new LogicException("提交失败");

                // 修改父级记录
                if ($parent_id > 0) {
                    $ptsr = app(TopicSpecialRecord::class)->whereUserId(request()->mid)->whereSpecialId($parent_id)->whereSpecialCode($special_code)->findOrEmpty();

                    $ptsr->right_count += 1;
                    $ptsr->accuracy    = round($ptsr->right_count / $ptsr->exam_count, 2) * 100;
                    $ptsr->create_time = $time;

                    if (!$ptsr->save()) throw new LogicException("提交失败");
                }
            }
        }
    }

    /**
     * 获取错题本
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-03-03
     *
     * @param $param
     * @return mixed
     */
    public function getWrongTopicList($param)
    {
        // 验证数据
        // $this->getValidate()->scene('wrong_list')->failException()->check($param);
        // 参数
        $mid = request()->mid;
        // 数据
        $field = 'id,topic_type,topic_id,wrong_count,question_type,(right_count+wrong_count) as answer_count,wrong_time';
        $list  = $this
            ->field($field)
            ->with(['topic_title'])
            ->whereUserId($mid)
            ->where('question_type', 'IN', '1,2,3,4,7')
            ->whereNotNull('wrong_time')
            // ->group('topic_id')
            ->order('wrong_time DESC')
            // ->buildSql()
            ->paginate($this->getListRows())
            ->append(['question_type_text'])
            ->each(function ($i) {
                $i->topic_title = app(Common::class)->removeMaterial($i->topic_title ?: '');
            });

        $redis = Cache::store('redis')->handler();
        if ($list->total()) {
            $topics = $this->whereUserId($mid)
                ->where('question_type', 'IN', '1,2,3,4,7')
                ->whereNotNull('wrong_time')
                ->field('id,topic_type,topic_id')
                ->order('wrong_time DESC')
                ->select()->toArray();
            $redis->hSet('user_wrong_topics', (string)request()->mid, serialize($topics));
        } else {
            $redis->hDel('user_wrong_topic', (string)request()->mid);
        }

        return $list;
    }

    /**
     * 获取错题本试题信息
     * Author 亓官雨树<lucky.max@foxmail.com>
     * Date 2021-03-03
     *
     * @param $param
     * @return array
     */
    public function getWrongTopic($param)
    {
        // 验证数据
        $this->getValidate()->scene('wrong_topic')->failException()->check($param);
        // 参数
        $record_id = $param['record_id'];
        $mid       = request()->mid;
        // 错题集
        $redis      = Cache::store('redis')->handler();
        $topics     = unserialize($redis->hGet('user_wrong_topics', (string)$mid));
        $record_id  = $record_id ?: (string)current($topics)['record_id'];
        $current    = array_search($record_id, array_column($topics, 'id'));
        $topic_id   = $topics[$current]['topic_id'];
        $topic_type = $topics[$current]['topic_type'];
        // 是否子题
        if (2 == $topic_type) {
            $topic_id = app(TopicMaterial::class)->whereId($topic_id)->value('topic_id');
        }
        // 数据
        $topic = app(Topic::class)->getTopicInfoById((string)$topic_id);
        //
        foreach ($topic as $v) {
            $v->next_record_id = null;
            if (false !== $current) {
                $next = $current + 1;
                $next != count($topics) && $v->next_record_id = $topics[$next]['id'];
            }
        }

        return $topic;
    }

}
